/*
 * Copyright:  2018 smarabbit studio.
 *
 *  Licensed under the Confluent Community License; you may not use this file
 *  except in compliance with the License.  You may obtain a copy of the License at
 *
 *  http://www.confluent.io/confluent-community-license
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 *  WARRANTIES OF ANY KIND, either express or implied.  See the License for the
 *  specific language governing permissions and limitations under the License.
 *
 *  @作   者： 黄开晖 (117227773@qq.com)
 *  @日   期:  2021年5月29日
 */
package com.massyframework.beanskin.runtime.modular;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.function.Predicate;
import java.util.stream.Collectors;

import com.massyframework.beanskin.ModuleIdentifier;
import com.massyframework.beanskin.ModuleRepository;
import com.massyframework.beanskin.RequireLibraryDescriptor;
import com.massyframework.beanskin.RequireLibraryDescriptors;
import com.massyframework.beanskin.license.License.Builder;
import com.massyframework.beanskin.service.ServiceRepositoryFactory;
import com.massyframework.beanskin.service.secure.SecureCapacity;
import com.massyframework.beanskin.util.classloading.ModuleClassLoader;

/**
 * 模块配置构建器
 * @author huangkh
 *
 */
public abstract class AbstractModuleBuilder 
	implements RequireLibraryDescriptors, SecureCapacity {
	
	protected Integer id;
	protected ModuleIdentifier identifier;
	protected String name;
	protected String description;
	protected Set<String> tags;
	
	protected String developerShortName;
	protected String developerName;
	protected String developerHomePage;
	
	protected List<RequireLibraryDescriptor> requires;
	protected ModuleRepository moduleRepository;
	protected ServiceRepositoryFactory serviceRepositoryFactory;
	protected ModuleClassLoader classLoader;
	
	private String publicKey;
	private String x509Name;
	private String x509Encrypted;
	private Set<String> decryptClassNames;
	private Set<String> decryptScriptFileNames;
	
	/**
	 * 无参构造方法
	 */
	public AbstractModuleBuilder() {
		this.id = ModuleIdGenerictor.INSTANCE.nextId();
	}
	
	/**
	 * 使用{@code id}构建新实例
	 * <p>
	 * 适用于可热拔插模块，保持原有编号
	 * @param id {@link Integer}
	 */
	protected AbstractModuleBuilder(Integer id) {
		this.id = Objects.requireNonNull(id, "\"id\" cannot be null.");
	}
	
	/**
	 * 获取模块标识符
	 * @return {@link ModuleIdentifier}
	 */
	public ModuleIdentifier getModuleIdentifier() {
		return this.identifier;
	}
	
	
	/**
	 * 设置解密支持
	 * @param publicKey {@link String}, 公钥
	 * @param x509Name {@link String}, x509证书名称，可以为null.
	 * @param x509Encrypted {@link String}, x509证书加密数据
	 * @param classNames {@link List},已加密的类名
	 * @param scriptFileNames {@link List},已加密的脚本文件
	 * @return {@link AbstractModuleBuilder}
	 */
	public AbstractModuleBuilder decryption(String publicKey, String x509Name, 
			String x509Encrypted, List<String> classNames, List<String> scriptFileNames) {
		if (publicKey != null && (classNames != null || scriptFileNames != null)) {
			this.publicKey = publicKey;
			this.x509Name = x509Name;
			this.x509Encrypted = x509Encrypted;
			this.decryptClassNames = 
					classNames == null ?
							new HashSet<String>():	new HashSet<String>(classNames);
			this.decryptScriptFileNames =
					scriptFileNames == null ?
							new LinkedHashSet<String>() :	new LinkedHashSet<String>(scriptFileNames);
		}
		return this;
	}
	
	/**
	 * 添加标签集
	 * @param value {@link Set}
	 * @return {@link AbstractModuleBuilder}
	 */
	public AbstractModuleBuilder addTags(Set<String> value) {
		this.tags = value;
		return this;
	}
	

	@Override
	public RequireLibraryDescriptor findByFilter(Predicate<RequireLibraryDescriptor> filter) {
		if (filter == null) return null;
		if (this.requires == null) return null;
		return this.requires.stream()
				.filter(filter)
				.findFirst()
				.orElse(null);
	}
	
	@Override
	public int size() {
		return this.requires.size();
	}

	/**
	 * 解密的公钥
	 * @return {@link String}
	 */
	@Override
	public String getPublicKey() {
		return this.publicKey;
	}
	
	
	
	@Override
	public String getX509Name() {
		return this.x509Name;
	}

	@Override
	public String getX509Encrypted() {
		return this.x509Encrypted;
	}

	@Override
	public boolean isDecryptClass(String className) {
		return this.decryptClassNames == null ?
				false:
					this.decryptClassNames.contains(className);
	}
	
	

	@Override
	public boolean isDecryptScriptFile(String fileName) {
		return this.decryptScriptFileNames == null ?
				false:
					this.decryptScriptFileNames.contains(fileName);
	}

	/**
	 * 需要解密的类名
	 * @return {@link String}
	 */
	@Override
	public Set<String> getDecryptClassNames(){
		return this.decryptClassNames;
	}
	
	@Override
	public Set<String> getDescryptScriptFileNames() {
		return this.decryptScriptFileNames;
	}

	@Override
	public List<RequireLibraryDescriptor> getRequires() {
		return this.requires == null ?
				Collections.emptyList() :
					Collections.unmodifiableList(this.requires);
	}

	@Override
	public List<RequireLibraryDescriptor> getRequires(Predicate<RequireLibraryDescriptor> filter) {
		if (filter == null) return Collections.emptyList();
		if (this.requires == null) return Collections.emptyList();
		
		return this.requires.stream()
				.filter(filter)
				.collect(Collectors.toList());
	}
	
	/**
	 * 设置模块标识符
	 * @param value {@link ModuleIdentifier}
	 * @return {@link Builder}
	 */
	public AbstractModuleBuilder identifier(ModuleIdentifier value) {
		this.identifier = value;
		return this;
	}
	
	/**
	 * 设置模块名称
	 * @param value {@link String}
	 * @return {@link Builder}
	 */
	public AbstractModuleBuilder name(String value) {
		this.name = value;
		return this;
	}
	
	/**
	 * 设置模块简介
	 * @param value {@link String}
	 * @return {@link Builder}
	 */
	public AbstractModuleBuilder description(String value) {
		this.description = value;
		return this;
	}
	
	
	
	/**
	 * 设置开发商
	 * @param shortName {@link String},简称
	 * @param name {@link String},全称
	 * @param homePage {@link String},主页
	 * @return {@link AbstractModuleBuilder}
	 */
	public AbstractModuleBuilder developer(String shortName, String name, String homePage) {
		this.developerShortName = shortName;
		this.developerName = name;
		this.developerHomePage = homePage;
		return this;
	}
	
	/**
	 * 设置模块资源库
	 * @param value {@link ModuleRepository}
	 * @return {@link AbstractModuleBuilder}
	 */
	public AbstractModuleBuilder moduleRepository(ModuleRepository value) {
		this.moduleRepository = value;
		return this;
	}
	
	/**
	 * 设置类加载器
	 * @param value {@link ModuleClassLoader}
	 * @return {@link AbstractModuleBuilder} 
	 */
	public AbstractModuleBuilder classLoader(ModuleClassLoader value) {
		this.classLoader = value;
		return this;
	}
	
	/**
	 * 设置服务资源库工厂
	 */
	public AbstractModuleBuilder serviceRepositoryFactory(ServiceRepositoryFactory value) {
		this.serviceRepositoryFactory =value;
		return this;
	}
	
	/**
	 * 添加要求存在模块的描述
	 * @param value {@link RequireLibraryDescriptor}
	 */
	public AbstractModuleBuilder addRequireLibrary(RequireLibraryDescriptor value) {
		if (value != null) {
			if (this.requires == null) {
				this.requires = new ArrayList<>();
			}
			this.requires.add(value);
		}
		return this;
	}

	
}
